﻿using Microsoft.ServiceBus.Messaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using GrayParrot.Core.Serialization;
using GrayParrot.Core.ServiceBus;
using GrayParrot.Core;
using GrayParrot.ServiceBus.Configuration;

namespace GrayParrot.ServiceBus
{
    /// <summary>
    /// Service Bus Message Bag
    /// </summary>
    /// <remarks>
    /// This class is used to carry business object onto the service bus infrastructure...
    /// </remarks>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    [DataContract(Namespace = "www.grayparrot.com")]
    public sealed class ServiceBusMessageBag<T> : ServiceBusMessageBagBase<T, BrokeredMessage>
        where T : class, new()
    {
        [DataMember]
        public DateTime DelayedDate { get; set; }

        [DataMember]
        public bool IsDelayed { get; set; }

        public ServiceBusMessageBag() : base()
        {
        }

        public ServiceBusMessageBag(string messageName) : base(messageName)
        {
        }

        /// <summary>
        /// Convert To the ServiceBus BrokeredMessage object...
        /// </summary>
        /// <remarks>
        /// The standard serialization format is Binary...
        /// </remarks>
        /// <returns>a BrokeredMessage object if success, null otherwise</returns>
        public override BrokeredMessage ToBrokeredMessage()
        {
            BrokeredMessage retValue = null;

            retValue = new BrokeredMessage(this);
            retValue.Properties["CorrelationID"] = this.CorrelationID;
            retValue.Properties["MessageName"] = this.MessageName;

            // case of delayed message...
            if (this.DelayedDate != default(DateTime))
            {
                retValue.MessageId = this.MessageID.ToString("N");
                retValue.ScheduledEnqueueTimeUtc = this.DelayedDate.ToUniversalTime();
            }

            return retValue;
        }

        /// <summary>
        /// Convert To the ServiceBus BrokeredMessage object with XML body...
        /// </summary>
        /// <returns>a BrokeredMessage object if success, null otherwise</returns>
        public BrokeredMessage ToXMLBrokeredMessage()
        {
            BrokeredMessage retValue = null;

            string m_xml = this.SerializeAsXml();

            retValue = new BrokeredMessage(m_xml);
            retValue.Properties["CorrelationID"] = this.CorrelationID;
            retValue.Properties["MessageName"] = this.MessageName;

            // case of delayed message...
            if (this.DelayedDate != default(DateTime))
            {
                retValue.MessageId = this.MessageID.ToString("N");
                retValue.ScheduledEnqueueTimeUtc = this.DelayedDate.ToUniversalTime();
            }

            return retValue;
        }

        /// <summary>
        /// Checks if the message is delayed...
        /// </summary>
        /// <returns></returns>
        public ReturnValue<bool> CheckDelayed()
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            try
            {
                retValue = DelayedMessagesHelper.CheckDelayedMessage(this.MessageID.ToString());
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        /// <summary>
        /// Determines whether [is delayed cancelled].
        /// </summary>
        /// <returns></returns>
        public ReturnValue<bool> IsDelayedCancelled()
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            try
            {
                ReturnValue<DelayedMessageStatus> m_res = DelayedMessagesHelper.CheckStatus(this.MessageID.ToString());
                if (m_res.HasValue && m_res.Value == DelayedMessageStatus.Cancelled)
                {
                    retValue.HasValue = true;
                    retValue.Value = true;
                }
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        /// <summary>
        /// Checks the delayed status.
        /// </summary>
        /// <returns></returns>
        public ReturnValue<DelayedMessageStatus> CheckDelayedStatus()
        {
            ReturnValue<DelayedMessageStatus> retValue = new ReturnValue<DelayedMessageStatus>(DelayedMessageStatus.None);

            try
            {
                retValue = DelayedMessagesHelper.CheckStatus(this.MessageID.ToString());
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        /// <summary>
        /// Sets the delayed message in elaboration.
        /// </summary>
        /// <returns></returns>
        public ReturnValue<bool> SetDelayedMessageInElaboration()
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            try
            {
                retValue = DelayedMessagesHelper.ElaboratesDelayedMessage(this.MessageID.ToString());
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        /// <summary>
        /// Sets the delayed message elaborated.
        /// </summary>
        /// <returns></returns>
        public ReturnValue<bool> SetDelayedMessageElaborated()
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            try
            {
                retValue = DelayedMessagesHelper.ElaboratedDelayedMessage(this.MessageID.ToString());
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        /// <summary>
        /// Sets the delayed message cancelled.
        /// </summary>
        /// <returns></returns>
        public ReturnValue<bool> SetDelayedMessageCancelled()
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            try
            {
                retValue = DelayedMessagesHelper.CancelDelayedMessage(this.MessageID.ToString());
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }
    }
}
